package geographer;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.font.FontRenderContext;
import java.awt.geom.AffineTransform;

import javax.swing.JPanel;

/**
 * Project #3
 * CS 2334, 010
 * 03/26/2014
 * <P>
 * This class represents a bar for the graphical display
 * </P>
 * @version 1.0
 */
public class Bar extends JPanel
{
	/*The serial number for this specific bar*/
	private static final long serialVersionUID = 1L;
	
	/*The height of the bar*/
	private int height;
	
	/*The region the bar is showing*/
	private String region;
	
	/*The value of the bar*/
	private String value;
	
	/*The reference height for the bar*/
	private static long heightRef = 1;
	
	/*The max height that a bar can reach*/
	private static final int MAX_HEIGHT = 400;
	
	/*The width of a bar*/
	private static final int WIDTH = 50;
	
	/*The padding of a bar*/
	private static final int PADDING = 5;
	
	/**
	 * The constructor for the <code>Bar</code> class.
	 * @param region     The region the bar is representing
	 * @param value      The value that the bar will show
	 */
	public Bar(String region, String value)
	{
		//Set the local values by the given parameters
		this.height = (int) (((Double.valueOf(value))/heightRef)*MAX_HEIGHT);
		if(height < 28)
			height = 28;
		this.region = region;
		this.value = value;
		
	}//end constructor
	
	/**
	 * Mutates the height reference for the bar
	 * @param value   The value to set the height reference to.
	 */
	public static void setHeightReference(String value){
		heightRef = Long.valueOf(value);
	}//end setHeightReference
	
	/**
	 * Draws the bar.
	 * <P>
	 * Algorithm:<br>
	 * 1. Call the super class <code>paintComponent</code> function.<br>
	 * 2. Define all the dimensions of the drawable component.<br>
	 * 3. Draw the component<br>
	 * </P>
	 * @params g    The graphics that will be used to draw the component
	 */
	@Override
	protected void paintComponent(Graphics g)
	{
		super.paintComponent(g);
		((Graphics2D) g).setRenderingHint(
						 	RenderingHints.KEY_ANTIALIASING,
							RenderingHints.VALUE_ANTIALIAS_ON);
		
		//Pixel dimensions of labels.
		Font fRegion = new Font("Helvetica", Font.ITALIC, 14);
		Font fValue =  new Font("Helvetica", Font.ITALIC, 10);
		AffineTransform aft = new AffineTransform();
		FontRenderContext frc = new FontRenderContext(aft, true, true);
		int vWidth  = (int) fValue.getStringBounds(value, frc).getWidth();
		int rWidth  = (int) fRegion.getStringBounds(region, frc).getWidth();
		int rHeight = (int) fRegion.getStringBounds(region, frc).getHeight();
		
		//Bar width-height and label padding
		int w = WIDTH, h = this.height, p = PADDING;
		
		//Bar color 
		float hue = 0.575f;
		
		//left and right vertex values
		int l = getWidth()/2-w/2, r = getWidth()/2+w/2;
		
		//top and bottom vertex values
		int t = getHeight()-h-p, b = getHeight()-3*p-rHeight;
		
		//Define vertices of the rectangle (bar).
		int[][] verts ={{l, l, r, r, r, r, l, l},
						{t, t, t, t, b, b, b, b},
						{0, w, 0, w, 0, w, 0, w}};
		
		//Project onto the x-y plane.
	    int[][]  prj = projXY(verts, -40*Math.PI/180);
	    
	    //Draw labels
	    g.setFont(fValue);
	    g.drawString(value, (prj[0][3]+prj[0][1])/2-vWidth/2, prj[1][1]-p);
	    g.setFont(fRegion);
	    g.drawString(region, getWidth()/2-rWidth/2, prj[1][4]+p+rHeight);
	    
	    //Draw right face
	    g.setColor(Color.getHSBColor(hue, 1f, 0.55f)); //Shade (dark)
		g.fillPolygon(	new int[]{prj[0][2], prj[0][3], prj[0][5], prj[0][4]},
						new int[]{prj[1][2], prj[1][3], prj[1][5], prj[1][4]},
						4);
		// Draw front face
		g.setColor(Color.getHSBColor(hue, 1f, 0.9f)); //Shade actual
		g.fillPolygon(	new int[]{prj[0][0], prj[0][2], prj[0][4], prj[0][6]},
						new int[]{prj[1][0], prj[1][2], prj[1][4], prj[1][6]},
						4);
		//Draw top face
		g.setColor(Color.getHSBColor(hue, 1f, 0.7f)); //Shade (mid dark)
		g.fillPolygon(	new int[]{prj[0][0], prj[0][1], prj[0][3], prj[0][2]},
						new int[]{prj[1][0], prj[1][1], prj[1][3], prj[1][2]},
						4);
	}//end paintComponent
	
	/**
	 * Calculates the projection for the drawable components
	 * <P>
	 * Algorithm:<br>
	 * 1. Define the matrix values<br>
	 * 2. Return the multiplied matrix values<br>
	 * </P>
	 * @param verts     The vertices of the components
	 * @param alpha     The alpha value associated with the component
	 */
	private static int[][] projXY(int[][] verts, double alpha){
		double[][] pXY = {{1,0,Math.cos(alpha)/2}, {0, 1, Math.sin(alpha)/2}};
		return matrixMultiplication(pXY, verts);
	}//end projXY
	
	/**
	 * Multiples the matrices.
	 * @param A  the first matrix
	 * @param B  the second matrix
	 * @return  product    The multiplied value of the matrices
	 */
	private static int[][] matrixMultiplication(double[][] A, int[][] B){
		if(A[0].length != B.length)
			return null;
		
		int [][] product = new int[A.length][B[0].length];
		
		//Each row of A
		for(int rowA=0; rowA < A.length; ++rowA) 					
			//Each column of B
			for(int columnB=0; columnB < B[0].length; ++columnB)
				//Each row of B
				for(int rowB=0; rowB < B.length; ++rowB)			
					product[rowA][columnB] += (int) (A[rowA][rowB]*B[rowB][columnB]);
		
		return product;
	}
}

